package com.songlanyun.modules.singlegoods.service.impl;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.songlanyun.common.config.SemaphoreTool;
import com.songlanyun.common.enums.GoodsConstant;
import com.songlanyun.common.enums.LockPrefixConstant;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.lock.DistributedLock;
import com.songlanyun.common.utils.BeanUtil;
import com.songlanyun.common.utils.PageUtils;
import com.songlanyun.common.utils.Query;
import com.songlanyun.common.utils.StrUtil;
import com.songlanyun.common.validator.ValidatorUtils;
import com.songlanyun.modules.exception.GoodsExceptionEnum;
import com.songlanyun.modules.group.entity.ProductGoodsGroupEntity;
import com.songlanyun.modules.group.service.ProductGoodsGroupService;
import com.songlanyun.modules.shop.service.ShopService;
import com.songlanyun.modules.singlegoods.dao.ProductSingleGoodsDao;
import com.songlanyun.modules.singlegoods.entity.ProductSingleGoodsEntity;
import com.songlanyun.modules.singlegoods.entity.ProductSingleGoodsStockRecordEntity;
import com.songlanyun.modules.singlegoods.entity.UnderStockRecordEntity;
import com.songlanyun.modules.singlegoods.model.OrderStockTo;
import com.songlanyun.modules.singlegoods.service.ProductSingleGoodsService;
import com.songlanyun.modules.singlegoods.service.ProductSingleGoodsStockRecordService;
import com.songlanyun.modules.singlegoods.service.SendUnderStockRecordMsgService;
import com.songlanyun.modules.singlegoods.service.UnderStockRecordService;
import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.constraints.Range;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 商家的单品
 */
@Service("productSingleGoodsService")
public class ProductSingleGoodsServiceImpl extends ServiceImpl<ProductSingleGoodsDao, ProductSingleGoodsEntity> implements ProductSingleGoodsService {

    @Autowired
    private ShopService shopService;
    @Autowired
    ProductGoodsGroupService productGoodsGroupService;

    @Autowired
    ProductSingleGoodsStockRecordService productSingleGoodsStockRecordService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private SendUnderStockRecordMsgService sendUnderStockRecordMsgService;

    @Autowired
    private UnderStockRecordService underStockRecordService;


    /**
     * 商家创建自家单品
     *
     * @param shopId
     * @param entity
     * @return
     */
    @Transactional
    public ProductSingleGoodsEntity add(Long shopId, ProductSingleGoodsEntity entity) {
        shopService.loadShopBy(shopId, true);
        entity.setShopId(shopId);
        entity = this.create(entity);
        if (entity.getAbleStock() > 0) {
            /**
             * 如果初始化的可用库存大于0，要记录初始入库记录
             */
            this.initStock(shopId, entity.getId(), entity.getAbleStock());
        }
        return entity;
    }

    /**
     * 商家查询自己的单品(查不出来会报错，如果逻辑删除也查不出来)
     *
     * @param shopId
     * @param id
     * @return
     */
    @Override
    public ProductSingleGoodsEntity getByShopIdAndId(Long shopId, Long id) {

        LambdaQueryWrapper<ProductSingleGoodsEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProductSingleGoodsEntity::getShopId, shopId)
                .eq(ProductSingleGoodsEntity::getId, id);
        ProductSingleGoodsEntity single = this.getOne(wrapper);
        if (single == null) {
            throw new RRException(GoodsExceptionEnum.SINGLE_GOODS_NOT_EXISTS);
        }
        return single;
    }

    /**
     * 商家查询自己的单品，如果被软删除也可以查出来
     *
     * @param shopId
     * @param id
     * @return
     */
    @Override
    public ProductSingleGoodsEntity loadByShopIdAndId(Long shopId, Long id) {

        ProductSingleGoodsEntity single = this.baseMapper.loadByShopIdAndId(shopId, id);

        if (single == null) {
            throw new RRException(GoodsExceptionEnum.SINGLE_GOODS_NOT_EXISTS);
        }
        return single;
    }


    /**
     * 商家修改自家单品
     *
     * @param shopId
     * @param entity
     * @return
     */
    @Transactional
    public ProductSingleGoodsEntity update(Long shopId, ProductSingleGoodsEntity entity) {
        shopService.loadShopBy(shopId, true);
        validateSingleGoodsExists(entity.getId());
        validateShopSafe(shopId, entity.getId());
        ProductSingleGoodsEntity entity1 = this.loadByIdForLock(shopId, entity.getId(), true);
        Integer ableStock = entity1.getAbleStock();
        BeanUtil.copyPropertiesIgnoreNull(entity, entity1);
        entity1.setAbleStock(ableStock);
        return this.modify(entity);
    }

    /**
     * 商家删除自家单品
     *
     * @param shopId
     * @param id
     * @return
     */
    @Transactional
    public void delete(Long shopId, Long id) {
        shopService.loadShopBy(shopId, true);
        validateSingleGoodsExists(id);
        validateShopSafe(shopId, id);
        this.remove(id);
    }


    /**
     * 创建单品
     *
     * @param entity
     * @return
     */
    @Override
    public ProductSingleGoodsEntity create(ProductSingleGoodsEntity entity) {
        ValidatorUtils.validateEntity(entity);
        validateGroupAndSetGroupName(entity);
        this.baseMapper.insert(entity);
        return entity;
    }


    /**
     * 修改单品
     *
     * @param entity
     * @return
     */
    @Override
    public ProductSingleGoodsEntity modify(ProductSingleGoodsEntity entity) {
        ValidatorUtils.validateEntity(entity);
        validateSingleGoodsExists(entity.getId());
        validateGroupAndSetGroupName(entity);
        this.baseMapper.updateById(entity);
        return this.getById(entity.getId());
    }

    /**
     * 删除单品
     *
     * @param id
     */
    @Override
    public void remove(Long id) {

        validateSingleGoodsExists(id);
        this.removeById(id);
    }

    /**
     * 分页查询单品
     *
     * @param params params参数说明
     *               shop_id 商家店铺id必给
     *               goods_group_id 商家店实商品分组id（可以不给，给只能给二级）
     *               title 单品标题，可以不给
     *               code 单品编码，可以不给
     *               page 当前第几页（默认第一页）
     *               limit 每页多少条 （默认每页10条）
     * @return
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        /**
         * 一定要有shop_id
         */
        Long shopId = MapUtil.getLong(params, "shop_id");
        QueryWrapper<ProductSingleGoodsEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("shop_id", shopId);

        Long goodsGroupId = MapUtil.getLong(params, "goods_group_id");
        if (goodsGroupId != null) {
            queryWrapper.eq("goods_group_id", goodsGroupId);
        }
        String title = params.getOrDefault("title", "").toString();
        if (StringUtils.isNotBlank(title)) {
            queryWrapper.like("title", title);
        }

        Integer added = MapUtil.getInt(params, "added");
        if (added != null) {
            queryWrapper.eq("added", added);
        }

        String code = params.getOrDefault("code", "").toString();
        if (StringUtils.isNotBlank(code)) {
            queryWrapper.like("code", code);
        }
        queryWrapper.orderByAsc("order_index");
        queryWrapper.orderByDesc("create_time");
        IPage<ProductSingleGoodsEntity> page = this.page(
                new Query<ProductSingleGoodsEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }


    //=============================入库行为======================================

    /**
     * 添加单品时如果可用库存大于，就需要调用初始化库存记录(内部调用)
     *
     * @return
     */
    private void initStock(Long shopId, Long singleGoodsId, int changeStock) {

        ProductSingleGoodsEntity singleGoods = this.loadByShopIdAndId(shopId, singleGoodsId);
        ProductSingleGoodsStockRecordEntity entity = initStockRecordSingleGoods(singleGoods);
        entity.setStockChangeMode(GoodsConstant.StockChangeMode.IN);
        entity.setInStockType(GoodsConstant.InStockType.INIT);
        entity.setStockChangeNum(changeStock);
        entity.setStockStartNum(0);
        entity.setStockEndNum(changeStock);
        entity.setCreateTime(new Date());

        productSingleGoodsStockRecordService.create(entity);
    }


    /**
     * 手动为单品增加库存
     *
     * @return
     */
    @DistributedLock(lockNamePre = LockPrefixConstant.SINGLE_GOODS, argNum = 2)
    @Transactional
    @Override
    public void manualInStock(Long shopId, Long singleGoodsId, int changeStock) {

        ProductSingleGoodsEntity singleGoods = null;
        int startNum = 0;
        singleGoods = this.loadByIdForLock(shopId, singleGoodsId, true);
        startNum = singleGoods.getAbleStock();
        //改变库存
        this.increaseStock(singleGoods, changeStock);

        ProductSingleGoodsStockRecordEntity entity = inStock(singleGoods, changeStock, startNum);
        entity.setInStockType(GoodsConstant.InStockType.MANUAL);
        entity.setRemark(String.format("手动为单品【%s】增加库存%d %s",
                singleGoods.getTitle(),
                changeStock,
                singleGoods.getUnit()));

        //增加手动入库记录
        productSingleGoodsStockRecordService.create(entity);

        //更新库存不足的单品记录状态
        sendUnderStockRecordMsgService.sendInStock(singleGoodsId);
    }


    //=============================出库行为======================================

    /**
     * 手动为单品减少库存
     *
     * @return
     */
    @DistributedLock(lockNamePre = LockPrefixConstant.SINGLE_GOODS, argNum = 2)
    @Transactional
    @Override
    public void manualOutStock(Long shopId, Long singleGoodsId, int changeStock) {

        ProductSingleGoodsEntity singleGoods = null;
        int startNum = 0;

        singleGoods = this.loadByIdForLock(shopId, singleGoodsId, false);
        if (singleGoods == null) {
            return;
        }
        startNum = singleGoods.getAbleStock();
        //减少单品可用库存
        this.decreaseStock(singleGoods, changeStock);

        ProductSingleGoodsStockRecordEntity entity = outStock(singleGoods, changeStock, startNum);
        entity.setOutStockType(GoodsConstant.OuterStockType.MANUAL);
        entity.setRemark(String.format("手动为单品【%s】减少库存%d %s", singleGoods.getTitle(), changeStock, singleGoods.getUnit()));
        productSingleGoodsStockRecordService.create(entity);


    }

    /**
     * 会员购买商品时扣掉库存
     *
     * @param shopId
     * @param orderStockTo
     */
    @Override
    public void orderOutStock(Long shopId, OrderStockTo orderStockTo) {

        ProductSingleGoodsEntity singleGoods = null;
        int startNum = 0;

        singleGoods = this.loadByIdForLock(shopId, orderStockTo.getSingleGoodsId(), false);
        if (singleGoods == null) {
            return;
        }
        if (singleGoods.getAbleStock() < orderStockTo.getChangeStock()) {
            //库存不足，发送mq消息保存记录
            sendUnderStockRecordMsgService.send(
                    new UnderStockRecordEntity(orderStockTo.getShopId(), orderStockTo.getGoodsId()
                            , orderStockTo.getSingleGoodsId(), orderStockTo.getSkuSetName(),
                            orderStockTo.getChangeStock(), singleGoods.getAbleStock())
            );

            String goodsTitle = StrUtil.truncation(orderStockTo.getGoodsTitle(), 10);
            String skuSetName = StrUtil.truncation(orderStockTo.getSkuSetName(), 10);
            throw new RRException(String.format("[%s]%s 库存不足%d%s",
                    goodsTitle,
                    skuSetName,
                    orderStockTo.getChangeStock(),
                    singleGoods.getUnit())
                    , GoodsExceptionEnum.SINGLE_GOODS_STOCK_SAFE.getCode());
        }
        startNum = singleGoods.getAbleStock();
        this.decreaseStock(singleGoods, orderStockTo.getChangeStock());


        ProductSingleGoodsStockRecordEntity entity = outStock(singleGoods, orderStockTo.getChangeStock(), startNum);
        entity.setOutStockType(GoodsConstant.OuterStockType.ORDER);
        entity.setOrderId(orderStockTo.getOrderId());
        entity.setChildReferId(orderStockTo.getChildReferId());
        entity.setOrderCode(orderStockTo.getOrderCode());
        entity.setRemark(String.format("订单编号[%s],会员[%s]购买商品【%s】%s 时,扣掉单品【%s】库存%d %s",
                orderStockTo.getOrderCode(),
                orderStockTo.getUserMobile(),
                orderStockTo.getGoodsTitle(),
                orderStockTo.getSkuSetName(),
                singleGoods.getTitle(),
                orderStockTo.getChangeStock(),
                singleGoods.getUnit()));

        productSingleGoodsStockRecordService.create(entity);

    }

    @Override
    public void cancelPayInStock(Long shopId, OrderStockTo orderStockTo, GoodsConstant.InStockType inStockType) {
        ProductSingleGoodsEntity singleGoods = null;
        int startNum = 0;

        singleGoods = this.loadByIdForLock(shopId, orderStockTo.getSingleGoodsId(), false);
        if (singleGoods == null) {
            return;
        }
        startNum = singleGoods.getAbleStock();
        this.increaseStock(singleGoods, orderStockTo.getChangeStock());


        ProductSingleGoodsStockRecordEntity entity = inStock(singleGoods, orderStockTo.getChangeStock(), startNum);
        entity.setInStockType(inStockType);
        entity.setOrderId(orderStockTo.getOrderId());
        entity.setChildReferId(orderStockTo.getChildReferId());
        entity.setOrderCode(orderStockTo.getOrderCode());

        if (inStockType.equals(GoodsConstant.InStockType.CANCEL_ORDER)) {
            entity.setRemark(String.format("订单编号[%s],会员[%s]撤销购买商品【%s】%s ,回退单品【%s】库存%d %s",
                    orderStockTo.getOrderCode(),
                    orderStockTo.getUserMobile(),
                    orderStockTo.getGoodsTitle(),
                    orderStockTo.getSkuSetName(),
                    singleGoods.getTitle(),
                    orderStockTo.getChangeStock(),
                    singleGoods.getUnit()));
        }

        if (inStockType.equals(GoodsConstant.InStockType.PAY_EXPIRE)) {
            entity.setRemark(String.format("订单编号[%s],支付过期撤销购买商品【%s】%s ,回退单品【%s】库存%d %s",
                    orderStockTo.getOrderCode(),
                    orderStockTo.getGoodsTitle(),
                    orderStockTo.getSkuSetName(),
                    singleGoods.getTitle(),
                    orderStockTo.getChangeStock(),
                    singleGoods.getUnit()));
        }


        productSingleGoodsStockRecordService.create(entity);
    }

    /**
     * 维权订单商家手动入库
     *
     * @param shopId
     * @param orderStockTo
     */
    @Override
    public void rightsChildOrderInStock(Long shopId, OrderStockTo orderStockTo) {
        ProductSingleGoodsEntity singleGoods = null;
        int startNum = 0;

        singleGoods = this.loadByIdForLock(shopId, orderStockTo.getSingleGoodsId(), false);
        if (singleGoods == null) {
            return;
        }
        startNum = singleGoods.getAbleStock();
        this.increaseStock(singleGoods, orderStockTo.getChangeStock());

        ProductSingleGoodsStockRecordEntity entity = inStock(singleGoods, orderStockTo.getChangeStock(), startNum);
        entity.setInStockType(GoodsConstant.InStockType.RETURN_GOODS);
        entity.setOrderId(orderStockTo.getOrderId());
        entity.setChildReferId(orderStockTo.getChildReferId());
        entity.setOrderCode(orderStockTo.getOrderCode());
        entity.setRightsId(orderStockTo.getRightsId());
        entity.setRightsCode(orderStockTo.getRightsCode());
        entity.setRightsChildId(orderStockTo.getRightsChildId());
        entity.setRemark(String.format("订单编号[%s],维权单编号[%s],商家入库商品【%s】%s ,回退单品【%s】库存%d %s",
                orderStockTo.getOrderCode(),
                orderStockTo.getRightsCode(),
                orderStockTo.getGoodsTitle(),
                orderStockTo.getSkuSetName(),
                singleGoods.getTitle(),
                orderStockTo.getChangeStock(),
                singleGoods.getUnit()));

        productSingleGoodsStockRecordService.create(entity);

    }

    @Override
    public void added(Long shopId, Long id) {
        ProductSingleGoodsEntity entity = this.loadByShopIdAndId(shopId, id);
        entity.setAdded(!entity.getAdded());
        this.modify(entity);
    }

    @Override
    public Integer rarelyGoodsNum(Long shopId, Integer num) {
        return this.baseMapper.rarelyGoodsNum(shopId, num);
    }

    @Override
    public ProductSingleGoodsEntity loadByIdForLock(Long shopId, Long id, boolean tw) {
        ProductSingleGoodsEntity entity = this.baseMapper.loadByIdForLock(shopId, id);
        if (entity == null && tw) {
            throw new RRException(GoodsExceptionEnum.SINGLE_GOODS_NOT_EXISTS);
        }
        return entity;
    }

    @Override
    public ProductSingleGoodsEntity loadByShopIdAndCount(Long shopId, String code) {
        return this.baseMapper.selectOne(new LambdaQueryWrapper<ProductSingleGoodsEntity>()
                .eq(ProductSingleGoodsEntity::getShopId,shopId)
                .eq(ProductSingleGoodsEntity::getCode,code)
                .last("limit 1"));
    }


    //========================================================================================================

    /**
     * 初始化记录的前单品容余部分
     *
     * @param single
     * @return
     */
    private ProductSingleGoodsStockRecordEntity initStockRecordSingleGoods(ProductSingleGoodsEntity single) {
        ProductSingleGoodsStockRecordEntity entity = new ProductSingleGoodsStockRecordEntity();
        entity.setShopId(single.getShopId());
        entity.setSingleGoodsId(single.getId());
        entity.setSingleGoodsTitle(single.getTitle());
        entity.setSingleGoodsCode(single.getCode());
        entity.setCoverImage(single.getCoverImage());
        entity.setUnit(single.getUnit());
        entity.setSku(single.getSku());
        return entity;
    }


    private ProductSingleGoodsStockRecordEntity inStock(ProductSingleGoodsEntity singleGoods, int changeStock, int startNum) {
        ProductSingleGoodsStockRecordEntity entity = initStockRecordSingleGoods(singleGoods);
        entity.setStockChangeMode(GoodsConstant.StockChangeMode.IN);
        entity.setStockChangeNum(changeStock);
        entity.setStockStartNum(startNum);
        entity.setStockEndNum(startNum + changeStock);
        entity.setCreateTime(new Date());
        return entity;
    }

    private ProductSingleGoodsStockRecordEntity outStock(ProductSingleGoodsEntity singleGoods, int changeStock, int startNum) {
        ProductSingleGoodsStockRecordEntity entity = initStockRecordSingleGoods(singleGoods);
        entity.setStockChangeMode(GoodsConstant.StockChangeMode.OUT);
        entity.setStockChangeNum(changeStock);
        entity.setStockStartNum(startNum);
        entity.setStockEndNum(startNum - changeStock);
        entity.setCreateTime(new Date());
        return entity;
    }

    /**
     * 1、验证商品分组是否存在
     * 2、只能关联商品分组的二级
     *
     * @param entity
     */
    private void validateGroupAndSetGroupName(ProductSingleGoodsEntity entity) {

        if (entity.getGoodsGroupId() > 0) {
            ProductGoodsGroupEntity load = productGoodsGroupService.getById(entity.getGoodsGroupId());
            if (load == null) {
                throw new RRException(GoodsExceptionEnum.PRODUCT_GROUP_NOT_EXISTS);
            }

            entity.setGoodsGroupName(load.getName());
        }

    }


    /**
     * 验证只能操作家单品数据
     *
     * @param shopId
     * @param id
     */
    private void validateShopSafe(Long shopId, Long id) {
        ProductSingleGoodsEntity load = this.getById(id);
        if (load != null && !load.getShopId().equals(shopId)) {
            throw new RRException(GoodsExceptionEnum.SINGLE_GOODS_SHOP_SAFE);
        }
    }

    /**
     * 验单品是否存在
     *
     * @param singleGoodsId
     */
    private void validateSingleGoodsExists(Long singleGoodsId) {
        ProductSingleGoodsEntity obj = this.getById(singleGoodsId);
        if (obj == null) {
            throw new RRException(GoodsExceptionEnum.SINGLE_GOODS_NOT_EXISTS);
        }
    }


    /**
     * 增加库存（注意该方法一定要放入有事务的方法中）
     *
     * @param entity
     * @param stock
     * @return
     */
    private ProductSingleGoodsEntity increaseStock(ProductSingleGoodsEntity entity, int stock) {

        entity.increaseStock(stock);
        this.baseMapper.setAbleStock(entity.getId(), entity.getAbleStock());
        return entity;

    }

    /**
     * 减少库存（注意该方法一定要放入有事务的方法中）
     *
     * @param entity
     * @param stock
     * @return
     */
    private ProductSingleGoodsEntity decreaseStock(ProductSingleGoodsEntity entity, int stock) {
        entity.decreaseStock(stock);
        this.baseMapper.setAbleStock(entity.getId(), entity.getAbleStock());
        return entity;
    }


}
